<!doctype html>
<html lang="en-US">
  <head>
    <link href="/assets/index.css" rel="stylesheet" type="text/css" />
    <link href="./css/pauseAnimation.css" rel="stylesheet" type="text/css" />
    <script crossorigin="anonymous" src="https://unpkg.com/react@16.8.6/umd/react.production.min.js"></script>
    <script crossorigin="anonymous" src="https://unpkg.com/react-dom@16.8.6/umd/react-dom.production.min.js"></script>
    <script crossorigin="anonymous" src="/test-harness.js"></script>
    <script crossorigin="anonymous" src="/test-page-object.js"></script>
    <script crossorigin="anonymous" src="/__dist__/webchat-es5.js"></script>
  </head>
  <body>
    <main id="webchat"></main>
    <script type="module">
      const streamingFormat = new URL(window.location.href).searchParams.get('streamingFormat') ?? 'channelData'; // can be entity or channelData

      function addLivestreamingMetadata(activity, livestreamingMetadata) {
        return streamingFormat === 'entity'
          ? {
              ...activity,
              entities: [...(activity.entities ?? []), { ...livestreamingMetadata, type: 'streaminfo' }]
            }
          : {
              ...activity,
              channelData: { ...activity.channelData, ...livestreamingMetadata }
            };
      }

      run(async function () {
        const {
          React: { createElement },
          ReactDOM: { render },
          WebChat: {
            Components: { BasicWebChat, Composer },
            decorator: { WebChatDecorator },
            hooks: { useActiveTyping, useActivityKeys, useGetActivitiesByKey }
          }
        } = window; // Imports in UMD fashion.

        const { directLine, store } = testHelpers.createDirectLineEmulator();
        let currentActivityKeysWithId = [];
        let currentActiveTyping = {};

        const Monitor = () => {
          const [activityKeys] = useActivityKeys();
          const [activeTyping] = useActiveTyping();
          const getActivitiesByKey = useGetActivitiesByKey();

          currentActivityKeysWithId = Object.freeze(
            activityKeys.map(key => [key, getActivitiesByKey(key).map(({ id }) => id)])
          );

          currentActiveTyping = activeTyping;

          return false;
        };

        render(
          createElement(
            WebChatDecorator,
            {},
            createElement(
              Composer,
              {
                directLine,
                store
              },
              createElement(BasicWebChat),
              createElement(Monitor)
            )
          ),
          document.getElementById('webchat')
        );

        await pageConditions.uiConnected();

        // SETUP: Bot sent a message.
        await directLine.emulateIncomingActivity({
          id: 'a-00001',
          from: { id: 'u-00001', name: 'Bot', role: 'bot' },
          text: 'Adipisicing cupidatat eu Lorem anim ut aute magna occaecat id cillum.',
          timestamp: 0,
          type: 'message'
        });

        let firstActivityKey = currentActivityKeysWithId[0][0];

        // WHEN: Bot is typing a message.
        const firstTypingActivityId = 't-00001';

        await directLine.emulateIncomingActivity(
          addLivestreamingMetadata(
            {
              from: { id: 'u-00001', name: 'Bot', role: 'bot' },
              id: firstTypingActivityId,
              text: 'A quick',
              timestamp: 1,
              type: 'typing'
            },
            { streamSequence: 1, streamType: 'streaming' }
          )
        );

        let secondActivityKey = currentActivityKeysWithId[1][0];

        // THEN: Should display 2 messages.
        await pageConditions.numActivitiesShown(2);
        expect(pageElements.typingIndicator()).toBeFalsy();
        expect(pageElements.activityContents()[0]).toHaveProperty(
          'textContent',
          'Adipisicing cupidatat eu Lorem anim ut aute magna occaecat id cillum.'
        );
        expect(pageElements.activityContents()[1]).toHaveProperty('textContent', 'A quick');
        await host.snapshot('local');

        // THEN: Should have 2 activity keys.
        expect(currentActivityKeysWithId).toEqual([
          [firstActivityKey, ['a-00001']],
          [secondActivityKey, ['t-00001']]
        ]);

        // THEN: Should have active typing.
        expect(currentActiveTyping).toEqual({
          'u-00001': {
            at: expect.any(Number),
            expireAt: expect.any(Number),
            name: 'Bot',
            role: 'bot',
            type: 'livestream'
          }
        });

        // ---

        // WHEN: Bot send typing message in out-of-order fashion.
        await directLine.emulateIncomingActivity(
          addLivestreamingMetadata(
            {
              from: { id: 'u-00001', name: 'Bot', role: 'bot' },
              id: 't-00003',
              text: 'A quick brown fox jumped over',
              timestamp: 3,
              type: 'typing'
            },
            { streamId: firstTypingActivityId, streamSequence: 3, streamType: 'streaming' }
          )
        );

        // THEN: Should display 2 messages.
        await pageConditions.numActivitiesShown(2);
        expect(pageElements.typingIndicator()).toBeFalsy();
        expect(pageElements.activityContents()[0]).toHaveProperty(
          'textContent',
          'Adipisicing cupidatat eu Lorem anim ut aute magna occaecat id cillum.'
        );
        expect(pageElements.activityContents()[1]).toHaveProperty('textContent', 'A quick brown fox jumped over');
        await host.snapshot('local');

        // THEN: Should have 2 activity keys only.
        expect(currentActivityKeysWithId).toEqual([
          [firstActivityKey, ['a-00001']],
          [secondActivityKey, ['t-00001', 't-00003']]
        ]);

        // THEN: Should have active typing.
        expect(currentActiveTyping).toEqual({
          'u-00001': {
            at: expect.any(Number),
            expireAt: expect.any(Number),
            name: 'Bot',
            role: 'bot',
            type: 'livestream'
          }
        });

        // ---

        // WHEN: Bot send the belated typing message.
        await directLine.emulateIncomingActivity(
          addLivestreamingMetadata(
            {
              from: { id: 'u-00001', name: 'Bot', role: 'bot' },
              id: 't-00002',
              text: 'A quick brown fox',
              timestamp: 2,
              type: 'typing'
            },
            { streamId: firstTypingActivityId, streamSequence: 2, streamType: 'streaming' }
          )
        );

        // THEN: Should display 2 messages without the belated typing message.
        await pageConditions.numActivitiesShown(2);
        expect(pageElements.typingIndicator()).toBeFalsy();
        expect(pageElements.activityContents()[0]).toHaveProperty(
          'textContent',
          'Adipisicing cupidatat eu Lorem anim ut aute magna occaecat id cillum.'
        );
        expect(pageElements.activityContents()[1]).toHaveProperty('textContent', 'A quick brown fox jumped over');
        await host.snapshot('local');

        // THEN: Should have 2 activity keys.
        expect(currentActivityKeysWithId).toEqual([
          [firstActivityKey, ['a-00001']],
          [secondActivityKey, ['t-00001', 't-00002', 't-00003']]
        ]);

        // THEN: Should have active typing.
        expect(currentActiveTyping).toEqual({
          'u-00001': {
            at: expect.any(Number),
            expireAt: expect.any(Number),
            name: 'Bot',
            role: 'bot',
            type: 'livestream'
          }
        });

        // ---

        // WHEN: Bot finished typing the message.
        await directLine.emulateIncomingActivity(
          addLivestreamingMetadata(
            {
              from: { id: 'u-00001', name: 'Bot', role: 'bot' },
              id: 'a-00002',
              text: 'A quick brown fox jumped over the lazy dogs.',
              type: 'message'
            },
            { streamId: firstTypingActivityId, streamType: 'final' }
          )
        );

        // THEN: Should display 2 messages.
        await pageConditions.numActivitiesShown(2);
        expect(pageElements.typingIndicator()).toBeFalsy();
        expect(pageElements.activityContents()[0]).toHaveProperty(
          'textContent',
          'Adipisicing cupidatat eu Lorem anim ut aute magna occaecat id cillum.'
        );
        expect(pageElements.activityContents()[1]).toHaveProperty(
          'textContent',
          'A quick brown fox jumped over the lazy dogs.'
        );
        await host.snapshot('local');

        // THEN: Should have 2 activity keys.
        expect(currentActivityKeysWithId).toEqual([
          [firstActivityKey, ['a-00001']],
          [secondActivityKey, ['t-00001', 't-00002', 't-00003', 'a-00002']]
        ]);

        // THEN: Should have no typing.
        expect(currentActiveTyping).toHaveProperty('u-00001', undefined);
      });
    </script>
  </body>
</html>
